package com.qian.service.ddj.serviceImpl;

import com.qian.api.ddj.model.CountQueryModel;
import com.qian.api.ddj.model.Order;
import com.qian.api.ddj.model.StatusDict;
import com.qian.api.ddj.service.ICashService;
import com.qian.api.ddj.service.ICountQueryService;
import com.qian.api.ddj.service.IHolidayService;
import com.qian.service.ddj.dao.*;
import com.qian.service.ddj.entity.*;
import com.yaowk.api.common.PageReq;
import com.yaowk.api.common.PageResp;
import com.yaowk.service.common.BaseRepository;
import com.yaowk.service.common.BaseServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.*;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.util.*;

@Service
public class CountQueryServiceImpl extends BaseServiceImpl<Order, DdjOrder, Integer> implements ICountQueryService {
    @Autowired
    private OrderRepository dao;
    @Autowired
    private UserRepository userDao;
    @PersistenceContext
    private EntityManager em;
    @Autowired
    private ICashService cashService;
    @Autowired
    private BusinessRepository businessDao;
    @Autowired
    private IHolidayService holidayService;
    @Autowired
    private ChannelRepository channelDao;
    @Autowired
    private BusinessGroupRepository businessGroupDao;

    public PageResp<Order> findAll(final CountQueryModel model, PageReq pageReq) {
        PageRequest pageRequest = new PageRequest(pageReq.getPageNumber() - 1, pageReq.getPageSize(), new Sort(Sort.Direction.DESC, "createTime"));
        Page<DdjOrder> page = dao.findAll(new Specification<DdjOrder>() {
            @Override
            public Predicate toPredicate(Root<DdjOrder> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Date> timePath = root.get("createTime");
                Path<Byte> payTypePath = root.get("payType");
                Root<DdjChannel> ddjChannelRoot = criteriaQuery.from(DdjChannel.class);

                Predicate condition = criteriaBuilder.isNotNull(root.<Integer>get("id"));
                // 用户比较
                if (isNotEmpty(model.getUserId()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.equal(root.<Integer>get("userId"), model.getUserId()));
                // 通道比较
                if (isNotEmpty(model.getChannelId()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.equal(ddjChannelRoot.<Integer>get("id"), model.getChannelId()));
                // 日期比较
                if (isNotEmpty(model.getIndexDate()) && isNotEmpty(model.getEndDate()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.between(timePath, model.getIndexDate(), model.getEndDate()));
                else if (isNotEmpty(model.getIndexDate()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.greaterThanOrEqualTo(timePath, model.getIndexDate()));
                else if (isNotEmpty(model.getEndDate()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.lessThanOrEqualTo(timePath, model.getEndDate()));
                // 支付类型比较
                if (isNotEmpty(model.getPayType()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.equal(root.<Byte>get("payType"), model.getPayType()));
                return condition;
            }
        }, pageRequest);

        PageResp<Order> pageResp = page2pageResp(page);
        for (Order order : pageResp.getList()) {
            DdjUser user = userDao.findOne(order.getUserId());
            order.setUsername(user.getUsername());
            if (isNotEmpty(order.getBusinessId())) {
                DdjBusiness ddjBusiness = businessDao.findOne(order.getBusinessId());
                order.setBusinessName(ddjBusiness.getName());
            }
        }
        return pageResp;
    }


    @Override
    protected BaseRepository getDao() {
        return dao;
    }

    @Override
    protected DdjOrder model2Entity(Order model) {
        if (ObjectUtils.isEmpty(model)) {
            return null;
        }
        DdjOrder order = new DdjOrder();
        order.setStatus(model.getStatus());
        order.setOrderNo(model.getOrderNo());
        order.setUpOrderNo(model.getUpOrderNo());
        order.setPayType(model.getPayType());
        order.setRealAmount(model.getRealAmount());
        order.setUserId(model.getUserId());
        order.setOutOrderNo(model.getOutOrderNo());
        order.setNotifyUrl(model.getNotifyUrl());
        order.setBusinessId(model.getBusinessId());
        order.setBody(model.getBody());
        order.setAmount(model.getAmount());
        order.setCreateTime(model.getCreateTime());
        order.setId(model.getId());
        order.setCode(model.getCode());
        order.setPayTime(model.getPayTime());
        order.setAmountFee(model.getAmountFee());
        return order;
    }

    @Override
    protected Order entity2model(DdjOrder entity) {
        if (ObjectUtils.isEmpty(entity)) {
            return null;
        }
        Order order = new Order();
        order.setStatus(entity.getStatus());
        order.setOrderNo(entity.getOrderNo());
        order.setUpOrderNo(entity.getUpOrderNo());
        order.setPayType(entity.getPayType());
        order.setRealAmount(entity.getRealAmount());
        order.setUserId(entity.getUserId());
        order.setOutOrderNo(entity.getOutOrderNo());
        order.setNotifyUrl(entity.getNotifyUrl());
        order.setBusinessId(entity.getBusinessId());
        order.setBody(entity.getBody());
        order.setAmount(entity.getAmount());
        order.setAmountFee(entity.getAmountFee());
        order.setCreateTime(entity.getCreateTime());
        order.setId(entity.getId());
        order.setCode(entity.getCode());
        order.setPayTime(entity.getPayTime());
        return order;
    }

    @Override
    public List<CountQueryModel> findOfBusiness(CountQueryModel model) {
        final List<Integer> businessId = new ArrayList<>();
        if (ObjectUtils.isEmpty(model.getBusinessId())) {
            if (ObjectUtils.isEmpty(model.getBusinessGroupId())) {
                if (isNotEmpty(model.getChannelId())) {
                    DdjChannel channel = channelDao.findOne(model.getChannelId());
                    for (DdjBusinessGroup ddjBusinessGroup : channel.getBusinessGroups()) {
                        for (DdjBusiness ddjBusiness : ddjBusinessGroup.getBusinesses()) {
                            businessId.add(ddjBusiness.getId());
                        }
                    }
                }
            } else {
                DdjBusinessGroup ddjBusinessGroup = businessGroupDao.findOne(model.getBusinessGroupId());
                for (DdjBusiness ddjBusiness : ddjBusinessGroup.getBusinesses()) {
                    businessId.add(ddjBusiness.getId());
                }
            }
        } else {
            businessId.add(model.getBusinessId());
        }

        List<DdjOrder> ddjOrders = dao.findAll(new Specification<DdjOrder>() {
            @Override
            public Predicate toPredicate(Root<DdjOrder> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Predicate condition = root.<Byte>get("status").in(StatusDict.SUCCESS_PAY, StatusDict.FINISH_PAY, StatusDict.SETTLEMENT);

                Path<Date> timePath = root.get("createTime");

                if (isNotEmpty(model.getChannelId()) && !CollectionUtils.isEmpty(businessId)) {
                    condition = criteriaBuilder.and(condition, root.<Integer>get("businessId").in(businessId));
                }
                // 日期比较
                if (isNotEmpty(model.getIndexDate()) && isNotEmpty(model.getEndDate()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.between(timePath, model.getIndexDate(), model.getEndDate()));
                else if (isNotEmpty(model.getIndexDate()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.greaterThanOrEqualTo(timePath, model.getIndexDate()));
                else if (isNotEmpty(model.getEndDate()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.lessThanOrEqualTo(timePath, model.getEndDate()));

                return condition;
            }
        });

        Map<Integer, CountQueryModel> result = new HashMap<>();
        for (DdjOrder ddjOrder : ddjOrders) {
            CountQueryModel countQueryModel = result.get(ddjOrder.getBusinessId());
            if (ObjectUtils.isEmpty(countQueryModel)) {
                countQueryModel = new CountQueryModel();
                DdjBusiness business = businessDao.findOne(ddjOrder.getBusinessId());
                countQueryModel.setBusinessId(ddjOrder.getBusinessId());
                countQueryModel.setBusinessName(business.getName());
                countQueryModel.setAccount(business.getAccount());
                countQueryModel.setAmount(new BigDecimal(0));
                result.put(ddjOrder.getBusinessId(), countQueryModel);
            }

            countQueryModel.setAmount(countQueryModel.getAmount().add(ddjOrder.getRealAmount()));
        }

        List<CountQueryModel> resultList = new ArrayList<>();
        for (Map.Entry<Integer, CountQueryModel> entry : result.entrySet()) {
            resultList.add(entry.getValue());
        }

        return resultList;

    }

    @Override
    @Transactional
    public List<CountQueryModel> find(CountQueryModel model) {
        final List<Integer> businessId = new ArrayList<>();
        if (ObjectUtils.isEmpty(model.getBusinessId())) {
            if (ObjectUtils.isEmpty(model.getBusinessGroupId())) {
                if (isNotEmpty(model.getChannelId())) {
                    DdjChannel channel = channelDao.findOne(model.getChannelId());
                    for (DdjBusinessGroup ddjBusinessGroup : channel.getBusinessGroups()) {
                        for (DdjBusiness ddjBusiness : ddjBusinessGroup.getBusinesses()) {
                            businessId.add(ddjBusiness.getId());
                        }
                    }
                }
            } else {
                DdjBusinessGroup ddjBusinessGroup = businessGroupDao.findOne(model.getBusinessGroupId());
                for (DdjBusiness ddjBusiness : ddjBusinessGroup.getBusinesses()) {
                    businessId.add(ddjBusiness.getId());
                }
            }
        } else {
            businessId.add(model.getBusinessId());
        }

        List<DdjOrder> ddjOrders = dao.findAll(new Specification<DdjOrder>() {
            @Override
            public Predicate toPredicate(Root<DdjOrder> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Predicate condition = root.<Byte>get("status").in(StatusDict.SUCCESS_PAY, StatusDict.FINISH_PAY, StatusDict.SETTLEMENT);

                Path<Date> timePath = root.get("createTime");
                // 用户比较
                if (isNotEmpty(model.getUserId()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.equal(root.<Integer>get("userId"), model.getUserId()));
                // 通道比较
                if (isNotEmpty(model.getChannelId()) && !CollectionUtils.isEmpty(businessId)) {
                    condition = criteriaBuilder.and(condition, root.<Integer>get("businessId").in(businessId));
                }
                // 日期比较
                if (isNotEmpty(model.getIndexDate()) && isNotEmpty(model.getEndDate()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.between(timePath, model.getIndexDate(), model.getEndDate()));
                else if (isNotEmpty(model.getIndexDate()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.greaterThanOrEqualTo(timePath, model.getIndexDate()));
                else if (isNotEmpty(model.getEndDate()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.lessThanOrEqualTo(timePath, model.getEndDate()));
                // 支付类型比较
                if (isNotEmpty(model.getPayType()))
                    condition = criteriaBuilder.and(condition, criteriaBuilder.equal(root.<Byte>get("payType"), model.getPayType()));
                return condition;
            }
        });

        // 整理数据
        Map<Integer, CountQueryModel> map = new HashMap<>();
        if (isNotEmpty(model.getChannelId()) && isNotEmpty(model.getUserId()) && isNotEmpty(model.getPayType())) {

            DdjChannel ddjChannel = channelDao.findOne(model.getChannelId());
            DdjUser ddjUser = userDao.findOne(model.getUserId());

            CountQueryModel countQueryModel = new CountQueryModel();
            countQueryModel.setChannel(ddjChannel.getName());
            countQueryModel.setUserName(ddjUser.getUsername());
            countQueryModel.setPayType(model.getPayType());
            countQueryModel.setAmount(new BigDecimal(0));

            map.put(null, countQueryModel);
            // 仅一条记录
            for (DdjOrder order : ddjOrders) {
                countQueryModel.setAmount(countQueryModel.getAmount().add(order.getAmount()));
            }

        } else if (isNotEmpty(model.getChannelId()) && isNotEmpty(model.getUserId())) {
            // 按支付方式分类
            DdjChannel ddjChannel = channelDao.findOne(model.getChannelId());
            DdjUser ddjUser = userDao.findOne(model.getUserId());

            for (DdjOrder ddjOrder : ddjOrders) {
                Integer payType = Integer.valueOf(ddjOrder.getPayType());
                if (!map.containsKey(payType)) {
                    CountQueryModel countQueryModel = new CountQueryModel();
                    countQueryModel.setChannel(ddjChannel.getName());
                    countQueryModel.setUserName(ddjUser.getUsername());
                    countQueryModel.setPayType(ddjOrder.getPayType());
                    countQueryModel.setAmount(new BigDecimal(0));
                    map.put(payType, countQueryModel);
                }
                CountQueryModel countQueryModel = map.get(payType);
                countQueryModel.setAmount(countQueryModel.getAmount().add(ddjOrder.getAmount()));
            }
        } else if (isNotEmpty(model.getChannelId())) {
            // 按用户分类
            DdjChannel ddjChannel = channelDao.findOne(model.getChannelId());

            for (DdjOrder ddjOrder : ddjOrders) {
                Integer key = ddjOrder.getUserId();
                if (!map.containsKey(key)) {
                    DdjUser ddjUser = userDao.findOne(ddjOrder.getUserId());
                    CountQueryModel countQueryModel = new CountQueryModel();
                    countQueryModel.setChannel(ddjChannel.getName());
                    countQueryModel.setUserName(ddjUser.getUsername());
                    countQueryModel.setAmount(new BigDecimal(0));
                    map.put(key, countQueryModel);
                }
                CountQueryModel countQueryModel = map.get(key);
                countQueryModel.setAmount(countQueryModel.getAmount().add(ddjOrder.getAmount()));
            }
        } else {
            // 按通道分类
            for (DdjOrder ddjOrder : ddjOrders) {
                Integer key = null;
                DdjBusiness ddjBusiness = null;
                if (isNotEmpty(ddjOrder.getBusinessId())) {
                    ddjBusiness = businessDao.findOne(ddjOrder.getBusinessId());
                    key = ddjBusiness.getBusinessGroup().getChannelId();
                }
                if (!map.containsKey(key)) {
                    CountQueryModel countQueryModel = new CountQueryModel();
                    if (isNotEmpty(ddjBusiness)) {
                        countQueryModel.setChannel(ddjBusiness.getBusinessGroup().getChannel().getName());
                    } else {
                        countQueryModel.setChannel("无");
                    }
                    countQueryModel.setUserName("全部");
                    countQueryModel.setAmount(new BigDecimal(0));
                    map.put(key, countQueryModel);
                }
                CountQueryModel countQueryModel = map.get(key);
                countQueryModel.setAmount(countQueryModel.getAmount().add(ddjOrder.getAmount()));
            }
        }

        // 转成list
        List<CountQueryModel> lists = new ArrayList<>();
        for (Map.Entry<Integer, CountQueryModel> entry : map.entrySet()) {
            lists.add(entry.getValue());
        }

        return lists;
    }
}
